/**
 * \file Lexer.h
 *
 * Asteriskos Compiler 1
 * Written 2010-2011, by Anthony Berlin and Alexander Carlqvist
 *
 * This file is part of ICC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LEXER_H
#define LEXER_H

#include "TranslationUnit.h"
#include "Token.h"

/// Lexer states.
enum State
{
    STATE_START,
    STATE_INT_LITERAL,
    STATE_STRING_LITERAL,
    STATE_IDENT,
    STATE_INVALID_TOKEN
};

class Lexer : public Object
{
public:
    /// Constructor for 'Lexer'.
    Lexer(TranslationUnit* transUnit, list<Error*>* errorList);

    /// Perform lexical analysis on the translation-unit associated with this lexer, and
    /// create a token stream for the parser to use.
    void analyse();

    /// Dump the token stream to disc.
    void dump_to_disc(string& appFileName) const;

    /// A pointer to the translation-unot on which to perform lexical analysis.
    TranslationUnit* m_transUnit;

    /// The token stream. It contains all the tokens that the lexer has tokenized.
    list<Token*>* m_tokenStream;

    /// The keyword hashtable.
    unordered_map<string, Token*> m_keywords;

private:
    /// Initialize the keyword hashtable.
    void init_keywords();

    /// Add a keyword into the keyword hashtable.
    void add_keyword(string name, TokenId type, bool isSpecifier);

    /// Report an error if there are any bracket mismatches.
    void report_bracket_mismatches(SourceLine* curLine);

    /// Find the next token in the translation unit, and return that token.
    Token* get_next_token(SourceLine* curLine);

    /// Get the next four characters from the current position. We always look ahead
    /// three additional characters (even when there aren't any characters left on the
    /// current line).
    void peek(SourceLine* curLine);

    /// State: Start forming a token.
    short unsigned int lex_state_start(SourceLine* curLine, Token* nextToken);

    /// State: Integer literal.
    bool lex_state_int_literal(SourceLine* curLine, Token* nextToken);

    /// State: Boolean literal.
    bool lex_state_bool_literal(SourceLine* curLine, Token* nextToken);

    /// State: String literal.
    bool lex_state_string_literal(SourceLine* curLine, Token* nextToken);

    /// State: Identifier.
    bool lex_state_ident(SourceLine* curLine, Token* nextToken);

    /// Return true if 'character' is a valid punctuator character.
    bool is_punctuator_char(char character) const;

    /// Current lexer state.
    State m_state;

    /// The character position in the current line.
    signed int m_pos;

    /// An array of the next four characters (starting from 'm_pos').
    char m_peek[4];

    /// Bracket depths. Used to keep track of brackets.
    signed int m_braceDepth;
    signed int m_squareDepth;
    signed int m_parenDepth;

    /// A pointer to the errorlist.
    list<Error*>* m_errorList;

    /// Last token that got tokenized.
    Token* m_lastToken;
};

#endif // LEXER_H
